﻿using System.Collections.Generic;
using System.IO;
using System.Lua.Serialization;
using System.Text;

using NUnit.Framework;

namespace System.Lua.Tests
{
    [TestFixture]
    public class LuaSerializerTest
    {
        [Test(Description = "Serialize a double into a Lua variable.")]
        public void SerializeDoubleTest()
        {
            const double refreshTime = 300;

            SerializeTest(refreshTime);
        }

        [Test(Description = "Serialize a boolean into a Lua variable.")]
        public void SerializeBooleanTest()
        {
            const bool enabled = true;

            SerializeTest(enabled);
        }

        [Test(Description = "Serialize a string into a Lua variable.")]
        public void SerializeStringTest()
        {
            const string statusText = "Dan has entered Azeroth.";

            SerializeTest(statusText);
        }

        [Test(Description = "Serialize an int into a Lua variable.")]
        public void SerializeIntTest()
        {
            const int maxTweets = 20;

            SerializeTest(maxTweets);
        }

        [Test(Description = "Serialize a DateTime into a Lua variable.")]
        public void SerializeDateTimeTest()
        {
            DateTime now = DateTime.Today;

            SerializeTest(now);
        }

        [Test(Description = "Serialize an array into a Lua variable.")]
        public void SerializeArrayTest()
        {
            int[] array = new[]
                        {
                            42, 31, 64
                        };

            SerializeTest(array);
        }

        [Test(Description = "Serialize a dictionary into a Lua variable.")]
        public void SerializeDictionaryStringKeyTest()
        {
            var dictionary = new Dictionary<string, string>
                             {
                                 { "Key1", "Value1" },
                                 { "Key2", "Value2" }
                             };

            SerializeTest(dictionary);
        }

        [Test(Description = "Serialize a dictionary into a Lua variable.")]
        public void SerializeDictionaryIntKeyTest()
        {
            var dictionary = new Dictionary<int, string>
                             {
                                 { 1, "Value1" },
                                 { 2, "Value2" }
                             };

            SerializeTest(dictionary);
        }

        [Test(Description = "Serialize a dictionary into a Lua variable.")]
        public void SerializeDictionaryStringKeyClassTest()
        {
            var dictionary = new Dictionary<string, AddOnOptions>
                             {
                                 { "Movement", new AddOnOptions { Enabled = false } },
                                 { "Achievements", new AddOnOptions { Enabled = true }}
                             };

            SerializeTest(dictionary);
        }

        [Test(Description = "Serialize an instance of a class into a Lua variable.")]
        public void SerializeClassTest()
        {
            var statusDetails = new StatusDetails
                                {
                                    RepliedTo = 12345,
                                    Text = "Hello from Lua!",
                                    StatusUpdated = DateTime.Today,
                                    User = new User
                                           {
                                               Name = "Gabor",
                                               Friends = new[]
                                                         {
                                                             new User { Name = "Dan" },
                                                             new User { Name = "Scott" }
                                                         }
                                           }
                                };

            SerializeTest(statusDetails);
        }

        [Test(Description = "Deserialize invalid Lua code.")]
        [ExpectedException(typeof(CouldNotInterpretException))]
        public void DeserializationErrorTest()
        {
            const string invalidLua = "statusText = 'This literal string is missing a closing quote";

            using (var stringReader = new StringReader(invalidLua))
            using (LuaReader luaReader = LuaReader.Create(stringReader))
            {
                LuaSerializer.Deserialize<string>(luaReader, "statusText");
            }
        }

        private static void SerializeTest<T>(T value)
        {
            var stringBuilder = new StringBuilder();

            // Create a new instance of the Lua writer
            using (var stringWriter = new StringWriter(stringBuilder))
            using (LuaWriter luaWriter = LuaWriter.Create(stringWriter))
            {
                LuaSerializer.Serialize(luaWriter, "testVariable", value);
            }

            using (var stringReader = new StringReader(stringBuilder.ToString()))
            using (LuaReader luaReader = LuaReader.Create(stringReader))
            {
                // Deserialize the refreshTime variable into a double
                T result = LuaSerializer.Deserialize<T>(luaReader, "testVariable");

                // Assert that the original and result values are equal
                Assert.AreEqual(value, result);
            }
        }
    }
}
